package com.xxx.zhujici;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;
import org.web3j.crypto.Wallet;
import org.web3j.crypto.WalletFile;
import org.web3j.crypto.WalletUtils;

import com.alibaba.fastjson.JSON;

import io.github.novacrypto.bip39.MnemonicGenerator;
import io.github.novacrypto.bip39.SeedCalculator;
import io.github.novacrypto.bip39.Words;
import io.github.novacrypto.bip39.wordlists.English;
import io.github.novacrypto.hashing.Sha256;
import sun.security.provider.SecureRandom;

public class EthZhujici {

	/**
	 * 生成ETH助记词
	 * @param passphrase：短语（非null，加盐用）
	 */
	public static void createMnemonic(String passphrase) {
		// 1.生成12位助记词
		StringBuilder sb = new StringBuilder();
		byte[] entropy = new byte[Words.TWELVE.byteLength()];
		new SecureRandom().engineNextBytes(entropy);
		new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, sb::append);
		String mnemonic = sb.toString();
		System.out.println("mnemonic:" + mnemonic);
		List<String> mnemonicList = Arrays.asList(mnemonic.split(" "));

		// 2.使用助记词生成钱包种子
		byte[] seed = new SeedCalculator().withWordsFromWordList(English.INSTANCE).calculateSeed(mnemonicList,
				passphrase);
		ECKeyPair ecKeyPair = ECKeyPair.create(Sha256.sha256(seed));
		String privateKey = ecKeyPair.getPrivateKey().toString(16);
		String publicKey = ecKeyPair.getPublicKey().toString(16);
		String address = Keys.getAddress(publicKey);
		System.out.println("privateKey: 0x" + privateKey);
		System.out.println("publicKey: " + publicKey);
		System.out.println("address: 0x" + address);
	}

	/**
	 * 创建ETH账户
	 */
	public static Map<String, Object> createAccount(String passphrase) {
		// 1.生成12位助记词
		StringBuilder sb = new StringBuilder();
		byte[] entropy = new byte[Words.TWELVE.byteLength()];
		new SecureRandom().engineNextBytes(entropy);
		new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, sb::append);
		String mnemonic = sb.toString();
		System.out.println("mnemonic:" + mnemonic);
		List<String> mnemonicList = Arrays.asList(mnemonic.split(" "));

		// 2.使用助记词生成钱包种子
		byte[] seed = new SeedCalculator().withWordsFromWordList(English.INSTANCE).calculateSeed(mnemonicList,
				passphrase);
		ECKeyPair ecKeyPair = ECKeyPair.create(Sha256.sha256(seed));
		String privateKey = "0x" + ecKeyPair.getPrivateKey().toString(16);
		String publicKey = ecKeyPair.getPublicKey().toString(16);
		String address = "0x" + Keys.getAddress(publicKey);

		// 3.创建钱包地址与密钥
		String filePath = System.getProperty("user.home") + File.separator + "keystore";
		String fileName = null;
		try {
			fileName = WalletUtils.generateWalletFile(passphrase, ecKeyPair, new File(filePath), false);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (fileName == null) {
			return null;
		}
		String accountFilePath = filePath + File.separator + fileName;

		Map<String, Object> resultMap = new LinkedHashMap<>();
		resultMap.put("mnemonic", mnemonic);
		resultMap.put("privateKey", privateKey);
		resultMap.put("publicKey", publicKey);
		resultMap.put("address", address);
		resultMap.put("accountFilePath", accountFilePath);
		return resultMap;
	}

	/**
	 * 导入助记词 
	 * 必须输入正确的passphrase（密码）和mnemonic，才能得到正确的秘钥对和地址信息，否则会生成一套新的地址和秘钥对
	 * 
	 * @param passphrase
	 * @param mnemonic
	 * @return
	 */
	public static Map<String, Object> importByMnemonic(String passphrase, String mnemonic) {
		Map<String, Object> resultMap = new LinkedHashMap<>();
		List<String> mnemonicList = Arrays.asList(mnemonic.split(" "));
		byte[] seed = new SeedCalculator().withWordsFromWordList(English.INSTANCE).calculateSeed(mnemonicList,
				passphrase);
		ECKeyPair ecKeyPair = ECKeyPair.create(Sha256.sha256(seed));
		String privateKey = ecKeyPair.getPrivateKey().toString(16);
		String publicKey = ecKeyPair.getPublicKey().toString(16);
		String address = "0x" + Keys.getAddress(publicKey);

		// 创建钱包地址与密钥
		String filePath = System.getProperty("user.home") + File.separator + "keystore";
		String fileName = null;
		try {
			fileName = WalletUtils.generateWalletFile(passphrase, ecKeyPair, new File(filePath), false);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (fileName == null) {
			return null;
		}
		String accountFilePath = filePath + File.separator + fileName;
		resultMap.put("mnemonic", mnemonic);
		resultMap.put("privateKey", privateKey);
		resultMap.put("publicKey", publicKey);
		resultMap.put("address", address);
		resultMap.put("accountFilePath", accountFilePath);
		return resultMap;
	}

	/**
	 * 导出账户
	 * @throws CipherException 
	 * @throws IOException 
	 */
	public static Map<String, Object> exportAccount(String passphrase, String walletFilePath) throws IOException, CipherException {
		Map<String, Object> resultMap = new LinkedHashMap<>();
//		Credentials credentials = loadAccount(walletFilePath, passphrase);
		Credentials credentials = WalletUtils.loadCredentials(passphrase, walletFilePath);
		ECKeyPair ecKeyPair = credentials.getEcKeyPair();
		boolean useFullScrypt = false;
		WalletFile walletFile = null;
		try {
			if (useFullScrypt) {
				walletFile = Wallet.createStandard(passphrase, ecKeyPair);
			} else {
				walletFile = Wallet.createLight(passphrase, ecKeyPair);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
//		String fileNameEx = getWalletFileName(walletFile);
		String fileNameEx = new File(walletFilePath).getName();	// 文件原名称
		System.out.println("walletFile:" + JSON.toJSONString(walletFile));
		System.out.println("fileNameEx:" + fileNameEx);
		resultMap.put("walletFile", walletFile);
		resultMap.put("fileName", fileNameEx);
		return resultMap;
	}

	/**
	 * main
	 * 
	 * @param args
	 * @throws CipherException 
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException, CipherException {
		// 创建助记词
		// createMnemonic("testa");

		// 创建账户
//		 System.out.println(createAccount("").toString());

		// 导入助记词
		 String mnemonic = "door word level decide razor brief artefact expect cute empower nice clap";
		 System.out.println(importByMnemonic("", mnemonic).toString());
		
		// 导出账户
//		String walletFilePath = "C:\\Users\\guweiqiang\\keystore\\UTC--2019-08-07T02-10-23.64000000Z--a93679146f752797c67a60926d45b51ac5709673.json";
//		System.out.println(exportAccount("testb", walletFilePath).toString());
	}

}
